/*
 * hlist.c
 *
 *  Created on: Nov 27, 2011
 *      Author: benoybose
 */

#include "hclist.h"

#include <gc.h>

hclist_node* hlist_node_create(void* item) {
    hclist_node* node = (hclist_node*) GC_MALLOC(sizeof (hclist_node));
    node->prev = 0;
    node->next = 0;
    node->data = item;
    return node;
}

hclist* hclist_create(const char* metadata) {
    hclist* list = (hclist*) GC_MALLOC(sizeof (hclist));
    list->count = 0;
    list->head = 0;
    list->tail = 0;
    list->metadata = metadata;
	return list;
}

void hclist_add(hclist* list, void* item) {
    hclist_node* node = hlist_node_create(item);
    if ((0 == list->head) && (0 == list->tail)) {
        list->head = node;
        list->tail = node;
        list->count = 1;
    } else if ((list->head == list->tail) &&
            (0 != list->head)) {
        list->tail = node;
        list->tail->prev = list->head;
        list->head->next = node;
        list->count++;
    } else {
        hclist_node* last = list->tail;
        list->tail = node;
        last->next = node;
        node->prev = last;
        list->count++;
    }
}

void hclist_delete(hclist* list, void* item) {
    if ((0 != list->head) && (0 != list->tail)) {
        if ((list->head == list->tail) &&
                (list->head->data == item)) {
            list->head = 0;
            list->tail = 0;
            list->count = 0;
        } else {
            hclist_node* node = 0;
            hclist_node* current = list->head;
            while (0 != current) {
                if (current->data == item) {
                    node = current;
                    break;
                }
                current = current->next;
            }
            if (0 != node) {
                if (list->head == node) {
                    list->head = list->head->next;
                    if (0 != list->head) {
                        list->head->prev = 0;
                    }
                    list->count--;
                } else if (list->tail == node) {
                    list->tail = list->tail->prev;
                    if (0 != list->tail) {
                        list->tail->next = 0;
                    }
                    list->count--;
                } else {
                    node->prev->next = node->next;
                    node->next->prev = node->prev;
                    list->count--;
                }
            }
        }
    }
}

void hclist_foreach(hclist* list, hlist_foreach_function_t foreach_function) {
    hclist_node* current = list->head;
    while (0 != current) {
        if (0 != foreach_function) {
            foreach_function(current->data);
            current = current->next;
        }
    }
}

void hclist_foreach_r(hclist* list, hlist_foreach_function_t foreach_function) {
    hclist_node* current = list->tail;
    while (0 != current) {
        if (0 != foreach_function) {
            foreach_function(current->data);
            current = current->prev;
        }
    }
}

int hclist_find(hclist* list, void* item) {
    hclist_node* current = list->head;
    int index = 0;
    while (0 != current) {
        if (current->data == item) {
            return (index);
        }
        current = current->next;
        index++;
    }
    return (-1);
}

int hclist_count(hclist* list) {
    return list->count;
}

const char* hclist_get_meatadata(hclist* list) {
    return list->metadata;
}

void* hclist_get_at(hclist* list, int index) {
    hclist_node* current = list->head;
    int current_index = 0;
    while (0 != current) {
        if (current_index == index) {
            return current->data;
        }
        current = current->next;
        current_index++;
    }
    return (0);
}


